package com.system.core.rest;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.net.ssl.SSLContext;

import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.config.ConnectionConfig;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.core5.util.Timeout;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.DefaultUriBuilderFactory;

@Configuration
public class RestTemplateConfig {

    private final static int MAX_CONN_TOTAL = 1000;
    private final static int MAX_CONN_PER_ROUTE = 1000;
    private final static int CONNECT_TIMEOUT = 30 * 1000;
    private final static int READ_TIMEOUT = 30 * 1000;
    
    @Bean
    RestTemplate restTemplateNoEncode(RestTemplateBuilder builder) {
        RestTemplate build = builder.build();
        DefaultUriBuilderFactory defaultUriBuilderFactory = new DefaultUriBuilderFactory();
        defaultUriBuilderFactory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.NONE);
        List<HttpMessageConverter<?>> messageConverters = build.getMessageConverters();
        
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        ArrayList<MediaType> mediaTypes = new ArrayList<>();
        mediaTypes.add(MediaType.APPLICATION_JSON);
        mediaTypes.add(new MediaType("text","javascript",Charset.forName("utf-8")));
        converter.setSupportedMediaTypes(mediaTypes);
        converter.setDefaultCharset(StandardCharsets.UTF_8);
        messageConverters.add(converter);
        build.setUriTemplateHandler(defaultUriBuilderFactory);
        return build;
    }
    
    @Bean
    RestTemplate restTemplate() throws Exception {
    	
    	SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(createIgnoreVerifySSL(),NoopHostnameVerifier.INSTANCE);
    	
        RequestConfig requestConfig = RequestConfig.custom()
        		.setAuthenticationEnabled(false)
                .setConnectionRequestTimeout(Timeout.ofMinutes(5L))
                .build();
        
        ConnectionConfig connectionConfig = ConnectionConfig.custom()
                .setConnectTimeout(Timeout.ofMinutes(5L)) // 设置连接超时为5分钟
                .build();
        
        var connManager = PoolingHttpClientConnectionManagerBuilder.create()
        		.setMaxConnTotal(MAX_CONN_TOTAL)
        		.setMaxConnPerRoute(MAX_CONN_PER_ROUTE)
        		.setDefaultConnectionConfig(connectionConfig)
        		.setSSLSocketFactory(sslSocketFactory)
        		.build();
        
        HttpClient httpClient = HttpClientBuilder.create()
        		.setConnectionManager(connManager)
        		.setDefaultRequestConfig(requestConfig)
        		.build();
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
        factory.setConnectTimeout(CONNECT_TIMEOUT);
//        factory.setReadTimeout(READ_TIMEOUT);
        

        RestTemplate restTemplate = new RestTemplate(factory);
        restTemplate.setErrorHandler(new ResponseErrorHandler() {
			
			@Override
			public boolean hasError(ClientHttpResponse response) throws IOException {
				return false;
			}
			
			@Override
			public void handleError(ClientHttpResponse response) throws IOException {
				
			}
		});
        
        MappingJackson2XmlHttpMessageConverter converter = new MappingJackson2XmlHttpMessageConverter();
        converter.setSupportedMediaTypes(Collections.singletonList(MediaType.APPLICATION_XML));
        converter.setDefaultCharset(StandardCharsets.UTF_8);
        
        List<HttpMessageConverter<?>> converters = restTemplate.getMessageConverters();
        converters.add(converter);
        return restTemplate;
    }

    
    public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {  
    	SSLContextBuilder builder = new SSLContextBuilder();
    	try {
			builder.loadTrustMaterial(null, new TrustStrategy() {
			    @Override
			    public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
			        return true;
			    }
			});
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
        return builder.build();  
    }

}
